﻿Imports System.IO
Imports System.Xml
Imports System.Globalization
Imports System.Threading
Imports System.Web.Script.Serialization

Public Class Reader

    Public firstLoad, userID, serverURL, url_navigation, htmlDefault, language_form, nodeChanged As String

    Public Structure SubscriptionsGroups
        Dim id As String
        Dim name As String
        Dim nbunread As String
    End Structure

    Public Structure FeedsGroups
        Dim id_group As String
        Dim id As String
        Dim name As String
        Dim url As String
        Dim is_spark As String
        Dim nbunread As String
    End Structure

    Public Structure ReadingLists
        Dim name As String
        Dim nbunread As Integer
        Dim xml As XmlDocument
    End Structure

    Public Class ItemsLists
        Implements IComparable
        Public id As String
        Public feed_id As String
        Public title As String
        Public author As String
        Public html As String
        Public htmlbeforecontent As String
        Public htmlcontent As String
        Public htmlaftercontent As String
        Public htmlwebbrowser As String
        Public url As String
        Public is_saved As String
        Public is_read As String
        Public created_on_time As String
        Public feed_name As String
        Public group_id As String
        Public group_name As String

        Public Function CompareTo(ByVal obj As Object) As Integer Implements IComparable.CompareTo
            Dim c As ItemsLists
            c = DirectCast(obj, ItemsLists)
            Return created_on_time.CompareTo(c.created_on_time)
        End Function
    End Class

    Public Structure HotLinksLists
        Public id As String
        Public feed_id As String
        Public item_id As String
        Public temperature As String
        Public is_item As String
        Public is_local As String
        Public is_saved As String
        Public title As String
        Public url As String
        Public item_ids As String
    End Structure

    Public Structure HotLinksItemsLists
        Public id As String
        Public feed_id As String
        Public title As String
        Public author As String
        Public html As String
        Public htmlbeforecontent As String
        Public htmlcontent As String
        Public htmlaftercontent As String
        Public htmlwebbrowser As String
        Public url As String
        Public is_saved As String
        Public is_read As String
        Public created_on_time As String
        Public feed_name As String
        Public group_id As String
        Public group_name As String
    End Structure

    Public ArrSubscriptionsGroup() As SubscriptionsGroups
    Public ArrFeedsGroup() As FeedsGroups
    Public ArrReadingList(4) As ReadingLists       ' 0 = read, 1 = unread, 2 = all, 3 = saved, 4 = hot
    Public ArrReadingListItems() As ItemsLists
    Public ArrHotLinksList() As HotLinksLists
    Public ArrHotLinksListItems() As HotLinksItemsLists

    Public xmlfeedread, xmlfeedunread As New XmlDocument
    Public oNodeSelected As TreeNode

    ' Below are dev level preferences variables, values can be changed if necessary
    Public Const SecretKey As String = "FeverRSS"  ' Key used to en crypt/decrypt user info file, must be 64 bits, 8 bytes.
    Public delta_hours_recup As Integer = 72     ' Maximum age in hours of the items for all read items feed processing
    Public refresh_period = 900000              ' Time interval in milliseconds between 2 automatic refreshs
    Public user_info_file As String = "reader-user.txt"
    Public htmlStyle As String = _
        "<style type=""text/css"">body {margin: 10px 20px 10px 20px; background-color: #f7f2e6; font-family: Segoe UI, Georgia, Times, serif;" & _
        "font-size: 11px;} a, a:visited, a:active {color: #665733;} h1 {font-family: Segoe UI, Helvetica, Arial, sans-serif; font-size: 16px; line-height: 1.5;} " & _
        "div.subtitle {font-family: Segoe UI, Helvetica, Arial, sans-serif;font-size: 11px; font-color: lightgrey; font-weight: bold}" & _
        "table.title {border:1px solid lightgrey; background-color: floralwhite; border-spacing: 10px; width:100%;} img{border-style: none;}</style>"

    Public Sub New()
        ' Set the form language from the user info file if it exists
        If File.Exists(Environ("AppData") & "\" & Application.ProductName & "\" & user_info_file) = True Then
            Dim decryptedXML As String
            Dim ObjXml As New XmlDocument()
            ' Get file user info content and decrypt it
            Dim objReader As New StreamReader(Environ("AppData") & "\" & Application.ProductName & "\" & user_info_file)
            decryptedXML = functions.Decrypt(objReader.ReadToEnd)
            objReader.Close()
            ObjXml.LoadXml(decryptedXML)
            Dim nodeLanguage As XmlNode = ObjXml.SelectSingleNode("/user/language")
            If nodeLanguage IsNot Nothing Then
                language_form = nodeLanguage.FirstChild.InnerText
                Thread.CurrentThread.CurrentUICulture = New CultureInfo(language_form)
            Else
                language_form = CultureInfo.CurrentCulture.ToString
                Thread.CurrentThread.CurrentUICulture = CultureInfo.CurrentCulture
            End If
        Else        ' No information, load the default'OS language
            language_form = CultureInfo.CurrentCulture.ToString
            Thread.CurrentThread.CurrentUICulture = CultureInfo.CurrentCulture
        End If
        ' This call is required by the Windows Form Designer.
        InitializeComponent()
    End Sub

    Private Sub Reader_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim xpos, ypos As Integer
        ' if  this is the first  time to load the form 
        ' dont set the size ( the form will load  with the size  in the designe)
        If Not My.Settings.Size.IsEmpty Then
            Me.Size = My.Settings.Size
        End If
        ' Check the right item of the language selection on the menu
        If language_form = "fr" Or InStr(language_form, "fr-") = 1 Then FrenchToolStripMenuItem.Checked = True Else EnglishToolStripMenuItem.Checked = True
        NotifyIcon.BalloonTipTitle = Me.Text
        Login.Close()
        TimerRefresh.Interval = refresh_period
        firstLoad = "1"
        ' Localize all items and saved items display of the treeview
        TreeViewMenu.Nodes(0).Nodes(0).Tag = My.Resources._code_all_items
        TreeViewMenu.Nodes(0).Nodes(1).Tag = My.Resources._code_saved
        ' Set ListView columns width
        ColumnHeader1.Width = ListView.Width - 10
        ColumnHeader2.Width = ListView.Width - 10
        ' Calculate Webbrowser picture box position to center it on the dedicated panel
        xpos = (PanelBrowser.Width / 2) - (WebbrowserBackImg.Width / 2)
        ypos = (PanelBrowser.Height / 2) - (WebbrowserBackImg.Height / 2)
        WebbrowserBackImg.Location = New Point(xpos, ypos)
        htmlDefault = My.Resources.reader_default
        WebBrowser.DocumentText = htmlDefault
        TimerShowForm.Start()
    End Sub

    Private Sub TimerShowForm_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TimerShowForm.Tick
        Dim ObjXml As New XmlDocument()
        Dim strmail As String
        Dim decryptedXML As String
        ' Get file user info content and decrypt it
        Dim objReader As New StreamReader(Environ("AppData") & "\" & Application.ProductName & "\" & user_info_file)
        decryptedXML = functions.Decrypt(objReader.ReadToEnd)
        objReader.Close()
        ObjXml.LoadXml(decryptedXML)
        serverURL = ObjXml.DocumentElement.SelectSingleNode("/user/server").InnerText
        strmail = ObjXml.DocumentElement.SelectSingleNode("/user/email").InnerText
        ObjXml = Nothing
        logout.Text = My.Resources._code_logoff & " (" & strmail & ")"
        LabelEtat.Text = ""
        TimerShowForm.Stop()
        TreeViewMenu.Nodes(0).Expand()
        DoWaitRefresh()
        InitializeReaderData()
        GetAllFeedDetails(delta_hours_recup)       ' In parameter, hour period of fetching items
        TreeViewMenu.Refresh()
        RefreshCounters()
        TreeViewMenu.Refresh()
        TreeViewMenu.SelectedNode = TreeViewMenu.Nodes(0).Nodes(0)
        firstLoad = "0"
    End Sub

    Private Sub Reader_Resize(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Resize
        Dim xpos, ypos As Integer
        PanelBrowserUp.Width = Me.Size.Width - PanelBrowserUp.Location.X
        PanelBrowserDown.Width = Me.Size.Width - PanelBrowserDown.Location.X
        ' Calculate Webbrowser picture box new position to center it on the dedicated panel
        xpos = (PanelBrowser.Width / 2) - (WebbrowserBackImg.Width / 2)
        ypos = (PanelBrowser.Height / 2) - (WebbrowserBackImg.Height / 2)
        WebbrowserBackImg.Location = New Point(xpos, ypos)
        If Me.WindowState = FormWindowState.Minimized Then
            NotifyIcon.Visible = True
            Me.Hide()
        End If
    End Sub

    Private Sub NotifyIcon_MouseClick(sender As Object, e As MouseEventArgs) Handles NotifyIcon.MouseClick
        NotifyIcon.ShowBalloonTip(1000)
    End Sub

    Private Sub NotifyIcon_BalloonTipClicked(sender As Object, e As EventArgs) Handles NotifyIcon.BalloonTipClicked
        Me.Show()
        Me.WindowState = FormWindowState.Normal
        Me.Focus()
        NotifyIcon.Visible = False
    End Sub

    Private Sub Reader_FormClosing(ByVal sender As System.Object,
                          ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles MyBase.FormClosing
        ' Save window size to restore it as is during next launch
        My.Settings.Size = Me.Size
        My.Settings.Save()

    End Sub

    Private Sub ModifyLanguage(lang As String)
        Dim ObjXml As New XmlDocument()
        Dim decryptedXML, encryptedXML As String
        ' Get file user info content and decrypt it
        Dim objReader As New StreamReader(Environ("AppData") & "\" & Application.ProductName & "\" & user_info_file)
        decryptedXML = functions.Decrypt(objReader.ReadToEnd)
        objReader.Close()
        ObjXml.LoadXml(decryptedXML)
        Dim nodeLanguage As XmlNode = ObjXml.SelectSingleNode("/user/language")
        nodeLanguage.InnerText = lang
        ' Encrypt modified XML
        encryptedXML = functions.Encrypt(ObjXml.InnerXml)
        ' Save encrypted XML to disk
        Dim objWriter As New StreamWriter(Environ("AppData") & "\" & Application.ProductName & "\" & user_info_file)
        objWriter.WriteLine(encryptedXML)
        objWriter.Close()
        Application.Restart()
    End Sub

    Private Sub TimerRefresh_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TimerRefresh.Tick
        RefreshReaderData()
        RefreshCounters()
    End Sub

    Private Sub RefreshNowToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles RefreshNowToolStripMenuItem.Click
        RefreshReaderData()
        RefreshCounters()
    End Sub

    Private Sub QuitToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles QuitToolStripMenuItem.Click
        Application.Exit()
    End Sub

    Private Sub EnglishToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles EnglishToolStripMenuItem.Click
        ' If the app is already in english, nothing to do
        If EnglishToolStripMenuItem.Checked = False Then
            language_form = "en"
            ModifyLanguage(language_form)
        End If
    End Sub

    Private Sub FrenchToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles FrenchToolStripMenuItem.Click
        ' If the app is already in french, nothing to do
        If FrenchToolStripMenuItem.Checked = False Then
            language_form = "fr"
            ModifyLanguage(language_form)
        End If
    End Sub

    Private Sub logout_LinkClicked(ByVal sender As System.Object, ByVal e As System.Windows.Forms.LinkLabelLinkClickedEventArgs) Handles logout.LinkClicked
        Dim fs As New FileInfo(Environ("AppData") & "\" & Application.ProductName & "\" & user_info_file)
        fs.Delete()
        Login.Show()
        Me.Close()
    End Sub

    Private Sub LinkLabelAll_LinkClicked(sender As Object, e As LinkLabelLinkClickedEventArgs) Handles LinkLabelAll.LinkClicked
        LinkLabelAll_LinkClick(TreeViewMenu.SelectedNode)
    End Sub

    Private Sub LinkLabelUnread_LinkClicked(sender As Object, e As LinkLabelLinkClickedEventArgs) Handles LinkLabelUnread.LinkClicked
        LinkLabelUnread_LinkClick(TreeViewMenu.SelectedNode)
    End Sub

    Private Sub LinkLabelAll_LinkClick(ByVal oNodeSelected As TreeNode)
        LinkLabelUnread.Font = New Font(LinkLabelUnread.Font, FontStyle.Regular)
        LinkLabelAll.Font = New Font(LinkLabelUnread.Font, FontStyle.Bold)
        DoList(ArrReadingList(2).xml, oNodeSelected)
    End Sub

    Private Sub LinkLabelUnread_LinkClick(ByVal oNodeSelected As TreeNode)
        LinkLabelUnread.Font = New Font(LinkLabelUnread.Font, FontStyle.Bold)
        LinkLabelAll.Font = New Font(LinkLabelUnread.Font, FontStyle.Regular)
        DoList(ArrReadingList(1).xml, oNodeSelected)
    End Sub

    Private Sub DoWaitRefresh()

        ListView.Items.Clear()
        ListView.TileSize = New Size(ListView.Width - 10, 28)   ' 28 is the minimum height to have 2 lines displayed

        Dim itemListTemp As ListViewItem = ListView.Items.Add(My.Resources._code_data_loading_in_progress & "...")
        With itemListTemp
            .Tag = "info"
            .Font = New Font(ListView.Font.Name, ListView.Font.Size, FontStyle.Bold)
            .SubItems.Add(My.Resources._code_operation_last_few_seconds)
        End With

        ListView.Refresh()

    End Sub

    Private Sub DoWaitRefreshStatus(ByVal theTag As String, ByVal theStatus As String)

        If theStatus = "new" Then
            Dim itemListTemp As ListViewItem = ListView.Items.Add(My.Resources._code_loading & " " & theTag & " ...")
            With itemListTemp
                .Tag = theTag
                .Font = New Font(ListView.Font.Name, ListView.Font.Size, FontStyle.Bold)
            End With
            ListView.Refresh()

        Else
            For i = 1 To ListView.Items.Count
                If ListView.Items(i).Tag = theTag Then
                    With ListView.Items(i)
                        .Font = New Font(ListView.Font.Name, ListView.Font.Size, FontStyle.Regular)
                        .Text = My.Resources._code_finished_loading & " " & theTag & "."
                    End With
                    ListView.Refresh()
                    Exit For
                End If
            Next
        End If
    End Sub

    Public Sub InitializeReaderData()
        Dim groupName, feedName, wdata, idfeed, subscriptions_word As String
        Dim i, j As Integer
        Dim ObjXml As New XmlDocument()

        Try
            i = 0
            DoWaitRefreshStatus(My.Resources._code_group_list, "new")
            ' Fetch all groups
            ' Request : [serverURL]?api=xml&groups
            wdata = functions.WRequest(serverURL & "/", "POST", "api=xml&groups&api_key=" & functions.APIKey)
            ObjXml.LoadXml(wdata)
            Dim nodeGroupsList As XmlNodeList = ObjXml.DocumentElement.SelectNodes("groups/group")
            ReDim ArrSubscriptionsGroup(nodeGroupsList.Count - 1)
            Dim GroupsList(nodeGroupsList.Count - 1) As String
            For Each node As XmlNode In nodeGroupsList
                ArrSubscriptionsGroup(i).id = node.SelectSingleNode("id").InnerText
                ArrSubscriptionsGroup(i).name = node.SelectSingleNode("title").InnerText
                GroupsList(i) = node.SelectSingleNode("title").InnerText
                i += 1
            Next
            GroupsList = functions.SortAlpha(GroupsList)
            subscriptions_word = My.Resources._code_subscriptions
            For i = 0 To UBound(GroupsList) - 1
                ' Add the group in subscriptions treeview
                If functions.AddFullPathToTreeView(TreeViewMenu, subscriptions_word & "\" & GroupsList(i)) = False Then
                    MessageBox.Show(My.Resources._code_error_creating_group_list)
                    Exit Sub
                End If
            Next
            TreeViewMenu.Nodes(1).Tag = subscriptions_word
            TreeViewMenu.Refresh()

            DoWaitRefreshStatus(My.Resources._code_group_list, "end")

            groupName = ""
            j = 0
            ReDim ArrFeedsGroup(0)
            ' Fetch all feeds and associate them with corresponding group names
            ' Request : [serverURL]?api=xml&feeds
            DoWaitRefreshStatus(My.Resources._code_feed_list, "new")
            wdata = functions.WRequest(serverURL & "/", "POST", "api=xml&feeds&api_key=" & functions.APIKey)
            ObjXml.LoadXml(wdata)
            Dim nodeFeedsList As XmlNodeList = ObjXml.DocumentElement.SelectNodes("feeds/feed")
            ' For each feed, look for the associated group name, from this XML structure :
            '<feeds_group>
            '    <group_id>1</group_id> 
            '    <feed_ids>1,2,3,4,5,6,7,8,9,10,11</feed_ids> 
            '</feeds_group>
            ' We have to fetch feed's URL, look at which feeds_group it belongs, 
            ' and retrieve the corresponding group name from the group_id and the identified feeds_group
            For Each node As XmlNode In nodeFeedsList
                ReDim Preserve ArrFeedsGroup(j)
                feedName = node.SelectSingleNode("title").InnerText
                idfeed = node.SelectSingleNode("id").InnerText
                ArrFeedsGroup(j).id = idfeed
                ArrFeedsGroup(j).name = feedName
                ArrFeedsGroup(j).url = node.SelectSingleNode("url").InnerText
                ArrFeedsGroup(j).is_spark = node.SelectSingleNode("is_spark").InnerText
                nodeGroupsList = ObjXml.DocumentElement.SelectNodes("feeds_groups/feeds_group")
                Dim feed_groups, group_id As String
                For Each nodeGroup As XmlNode In nodeGroupsList
                    group_id = nodeGroup.SelectSingleNode("group_id").InnerText
                    feed_groups = nodeGroup.SelectSingleNode("feed_ids").InnerText
                    If Array.IndexOf(feed_groups.Split(","), idfeed) >= 0 Then
                        For i = 0 To UBound(ArrSubscriptionsGroup)
                            If ArrSubscriptionsGroup(i).id = group_id Then
                                ArrFeedsGroup(j).id_group = group_id
                                groupName = ArrSubscriptionsGroup(i).name
                                Exit For
                            End If
                        Next
                        Exit For
                    End If
                Next
                ' To be considered, a feed mustn't be marked as "spark" (Fever feature)
                If node.SelectSingleNode("is_spark").InnerText = "0" Then
                    ' Addition of the item
                    If functions.AddFullPathToTreeView(TreeViewMenu, TreeViewMenu.Nodes(1).Tag & "\" & groupName & "\" & feedName) Then
                        ' Node inserted
                        Dim NewFeedNode As New TreeNode
                        NewFeedNode = functions.TreeviewGetNodeByPath(TreeViewMenu, TreeViewMenu.Nodes(1).Tag & "\" & groupName & "\" & feedName)
                        NewFeedNode.Parent.Tag = groupName
                        NewFeedNode.Tag = feedName
                        TreeViewMenu.Nodes(1).Nodes(i).Tag = GroupsList(i)
                    Else
                        MessageBox.Show("Error creating feed list.")
                        Exit Sub
                    End If

                End If
                j += 1

            Next

            TreeViewMenu.Nodes(1).Expand()
            TreeViewMenu.Refresh()

            DoWaitRefreshStatus(My.Resources._code_feed_list, "end")

        Catch ex As Exception
            MessageBox.Show(My.Resources._code_error_creating_feed_list & " " & ex.Message)
        End Try
    End Sub

    ' Fetch détail of all the items stored on the server
    Public Sub GetAllFeedDetails(duration As String)
        Dim wdata, feed_id, feed_name, feed_url, group_name, group_id, max_id, last_request, old_elem, is_spark As String
        Dim ObjXml As New XmlDocument
        feed_name = ""
        feed_url = ""
        feed_id = ""
        group_name = ""
        group_id = ""
        is_spark = ""
        max_id = 0

        ' Explanation of these 2 last variables : the request doesn't return items in a strict chronological order, 
        ' we can't stop on the first older item then the defined period, so we have to make other requests
        ' to fetch items on the defined period. It seems that 5 more requests of 50 items each are enough
        ' to retrieve such items, this limit allows to avoid having to scan the whole database which can take a long time.
        ' The old_elem variable is used (value = 1) to report presence of at least one too old item in the request 
        ' processed and lowers the counter of extra requests by one.
        old_elem = 0
        last_request = 5

        DoWaitRefreshStatus(My.Resources._code_database_items, "new")

        Try

            ' Create read feeds XML root
            Dim dec As XmlDeclaration = xmlfeedread.CreateXmlDeclaration("1.0", Nothing, Nothing)
            xmlfeedread.AppendChild(dec)
            Dim response As XmlElement = xmlfeedread.CreateElement("response")
            xmlfeedread.AppendChild(response)
            Dim items As XmlElement = xmlfeedread.CreateElement("items")
            response.AppendChild(items)
            ' Clone read items root XML to build unread feeds one 
            xmlfeedunread = xmlfeedread.Clone

            Dim difftimestampend As Long = duration * 3600
            Dim dt As DateTime = DateTime.UtcNow
            Dim timestampnow = functions.DateToTimestamp(dt)
            Dim timestampend = timestampnow - difftimestampend

            ' Fetch a first batch of 50 of all items in database 
            ' Request : [serverURL]?api=xml&items&max_id=0
            wdata = functions.WRequest(serverURL & "/", "POST", "api=xml&items&max_id=" & max_id & "&api_key=" & functions.APIKey)
            ObjXml.LoadXml(wdata)
            Dim nodeItems As XmlNodeList = ObjXml.DocumentElement.SelectNodes("items/item")

            Do Until nodeItems.Count = 0
                For Each node As XmlNode In nodeItems
                    ' Process the item only if it is in the fetch period
                    max_id = node.SelectSingleNode("id").InnerText
                    If node.SelectSingleNode("created_on_time").InnerText >= timestampend Then
                        ' Look for the name and the URL of the feed corresponding to the feed_id, and the ID and the name of the feed group
                        max_id = node.SelectSingleNode("id").InnerText
                        feed_id = node.SelectSingleNode("feed_id").InnerText
                        For i = 0 To UBound(ArrFeedsGroup)
                            If ArrFeedsGroup(i).id = feed_id Then
                                feed_name = ArrFeedsGroup(i).name
                                feed_url = ArrFeedsGroup(i).url
                                is_spark = ArrFeedsGroup(i).is_spark
                                For j = 0 To UBound(ArrSubscriptionsGroup)
                                    If ArrFeedsGroup(i).id_group = ArrSubscriptionsGroup(j).id Then
                                        group_id = ArrSubscriptionsGroup(j).id
                                        group_name = ArrSubscriptionsGroup(j).name
                                        Exit For
                                    End If
                                Next
                                Exit For
                            End If
                        Next
                        Dim elem_feed As XmlElement = ObjXml.CreateElement("feed_name")
                        elem_feed.InnerText = feed_name
                        node.AppendChild(elem_feed)
                        Dim elem_url_feed As XmlElement = ObjXml.CreateElement("feed_url")
                        elem_url_feed.InnerText = feed_url
                        node.AppendChild(elem_url_feed)
                        Dim elem_group_id As XmlElement = ObjXml.CreateElement("group_id")
                        elem_group_id.InnerText = group_id
                        node.AppendChild(elem_group_id)
                        Dim elem_group As XmlElement = ObjXml.CreateElement("group_name")
                        elem_group.InnerText = group_name
                        node.AppendChild(elem_group)

                        If is_spark = "0" Then      ' Add the item in the list only if it doesn't belong to a spark feed
                            If node.SelectSingleNode("is_read").InnerText = "0" Then
                                Dim newnode = xmlfeedunread.ImportNode(node, True)
                                xmlfeedunread.DocumentElement.Item("items").AppendChild(newnode)
                            Else
                                Dim newnode = xmlfeedread.ImportNode(node, True)
                                xmlfeedread.DocumentElement.Item("items").AppendChild(newnode)
                            End If
                        End If
                        If last_request = 0 Then Exit Do

                    Else
                        ' Reports the presence of at least one too old item in the list returned by the request
                        old_elem = 1
                    End If

                Next

                ' If there was at least one too old item, decrease the number of extra requests allowed
                If old_elem = 1 Then
                    last_request = last_request - 1
                    old_elem = 0
                End If
                ' If all the extra requests have been made, exit the request loop
                If last_request = 0 Then Exit Do

                ' Fetch a next batch of 50 of all items in database 
                wdata = functions.WRequest(serverURL & "/", "POST", "api=xml&items&max_id=" & max_id & "&api_key=" & functions.APIKey)
                ObjXml.LoadXml(wdata)
                nodeItems = ObjXml.DocumentElement.SelectNodes("items/item")

            Loop

        Catch ex As Exception
            MessageBox.Show(My.Resources._code_error_retrieving_initial_database_items & " " & ex.Message)
        End Try

        DoWaitRefreshStatus(My.Resources._code_database_items, "end")

    End Sub

    Public Sub RefreshReaderData()
        Dim groupName, feedName, idfeed, wdata As String
        Dim i, j As Integer
        Dim ObjXml As New XmlDocument()

        Try
            i = 0
            ' Fetch all the groups
            ' Request : [serverURL]?api=xml&groups
            wdata = functions.WRequest(serverURL & "/", "POST", "api=xml&groups&api_key=" & functions.APIKey)
            ObjXml.LoadXml(wdata)
            Dim nodeGroupsList As XmlNodeList = ObjXml.DocumentElement.SelectNodes("groups/group")
            ReDim ArrSubscriptionsGroup(nodeGroupsList.Count - 1)
            Dim GroupsList(nodeGroupsList.Count - 1) As String
            For Each node As XmlNode In nodeGroupsList
                ArrSubscriptionsGroup(i).id = node.SelectSingleNode("id").InnerText
                ArrSubscriptionsGroup(i).name = node.SelectSingleNode("title").InnerText
                GroupsList(i) = node.SelectSingleNode("title").InnerText
                i += 1
            Next
            GroupsList = functions.SortAlpha(GroupsList)
            ' Add the group in the subscriptions treeview if it doesn't already exist
            For i = 0 To UBound(GroupsList) - 1
                If functions.AddFullPathToTreeView(TreeViewMenu, TreeViewMenu.Nodes(1).Tag & "\" & GroupsList(i)) = False Then
                    MessageBox.Show(My.Resources._code_error_while_updating_group_list)
                    Exit Sub
                End If
                TreeViewMenu.Refresh()
            Next

            j = 0
            groupName = ""
            ReDim ArrFeedsGroup(0)
            ' Fetch all the feeds and associate them with corresponding group names
            ' Request : [serverURL]?api=xml&feeds
            wdata = functions.WRequest(serverURL & "/", "POST", "api=xml&feeds&api_key=" & functions.APIKey)
            ObjXml.LoadXml(wdata)
            Dim nodeFeedsList As XmlNodeList = ObjXml.DocumentElement.SelectNodes("feeds/feed")
            ' For each feed, look for the associated group name, from this XML structure :
            '<feeds_group>
            '    <group_id>1</group_id> 
            '    <feed_ids>1,2,3,4,5,6,7,8,9,10,11</feed_ids> 
            '</feeds_group>
            ' We have to fetch feed's URL, look at which feeds_group it belongs, 
            ' and retrieve the corresponding group name from the group_id and the identified feeds_group
            For Each node As XmlNode In nodeFeedsList
                ReDim Preserve ArrFeedsGroup(j)
                feedName = node.SelectSingleNode("title").InnerText
                idfeed = node.SelectSingleNode("id").InnerText
                ArrFeedsGroup(j).id = idfeed
                ArrFeedsGroup(j).name = feedName
                ArrFeedsGroup(j).url = node.SelectSingleNode("url").InnerText
                ArrFeedsGroup(j).is_spark = node.SelectSingleNode("is_spark").InnerText
                nodeGroupsList = ObjXml.DocumentElement.SelectNodes("feeds_groups/feeds_group")
                Dim feed_groups, group_id As String
                For Each nodeGroup As XmlNode In nodeGroupsList
                    group_id = nodeGroup.SelectSingleNode("group_id").InnerText
                    feed_groups = nodeGroup.SelectSingleNode("feed_ids").InnerText
                    If Array.IndexOf(feed_groups.Split(","), idfeed) >= 0 Then
                        For i = 0 To UBound(ArrSubscriptionsGroup)
                            If ArrSubscriptionsGroup(i).id = group_id Then
                                ArrFeedsGroup(j).id_group = group_id
                                groupName = ArrSubscriptionsGroup(i).name
                                Exit For
                            End If
                        Next
                        Exit For
                    End If
                Next

                ' To be considered, a feed mustn't be marked as "spark" (Fever feature)
                If node.SelectSingleNode("is_spark").InnerText = "0" Then

                    ' Add the feed if it doesn't already exist
                    If functions.TreeviewGetNodeByPath(TreeViewMenu, TreeViewMenu.Nodes(1).Tag & "\" & groupName & "\" & feedName) Is Nothing Then
                        If functions.AddFullPathToTreeView(TreeViewMenu, TreeViewMenu.Nodes(1).Tag & "\" & groupName & "\" & feedName) Then
                            ' Node inserted
                            Dim NewFeedNode As New TreeNode
                            NewFeedNode = functions.TreeviewGetNodeByPath(TreeViewMenu, TreeViewMenu.Nodes(1).Tag & "\" & groupName & "\" & feedName)
                            NewFeedNode.Parent.Tag = groupName
                            NewFeedNode.Tag = feedName
                            TreeViewMenu.Nodes(1).Nodes(i).Tag = GroupsList(i)
                        Else
                            MessageBox.Show(My.Resources._code_error_while_updating_feed_list)
                            Exit Sub
                        End If
                    End If
                End If
                j += 1

            Next

        Catch ex As Exception
            MessageBox.Show(My.Resources._code_error_while_updating_data & " " & ex.Message)
        End Try
    End Sub

    Public Sub RefreshCounters()
        Dim wdata, unreadIds, savedIds, nbSaved As String
        Dim unreadAll As Integer
        Dim ObjXmlUnreadCount, ObjXMLlistUnread, ObjXMLListRead, ObjXMLListFromDate, ObjXMLList, _
            ObjXmlSaved, xmlSaved, xmlRead, xmlUnread As New XmlDocument

        ' Refresh unread items counters by feeds and groups, also
        ' "all items" et "saved". "Hot" list is not taken into account (dynamic list)

        Try
            If firstLoad = "1" Then DoWaitRefreshStatus(My.Resources._code_saved_items_list, "new")
            ' Fetch saved items number
            ' Request : [serverURL]?api=xml&saved_item_ids
            wdata = functions.WRequest(serverURL & "/", "POST", "api=xml&saved_item_ids&api_key=" & functions.APIKey)
            ObjXmlSaved.LoadXml(wdata)
            savedIds = ObjXmlSaved.DocumentElement.SelectSingleNode("saved_item_ids").InnerText
            If savedIds = "" Then
                nbSaved = 0
                ' Create a new XML document
                xmlSaved = New XmlDocument
                Dim dec As XmlDeclaration = xmlSaved.CreateXmlDeclaration("1.0", Nothing, Nothing)
                xmlSaved.AppendChild(dec)
                Dim response As XmlElement = xmlSaved.CreateElement("response")
                xmlSaved.AppendChild(response)
                Dim items As XmlElement = xmlSaved.CreateElement("items")
                response.AppendChild(items)
            Else
                nbSaved = savedIds.Split(",").Count
                ' Call the fetching XML feed of searched items function
                xmlSaved = functions.GetFeedXML(savedIds, "saved")
            End If
            ArrReadingList(3).name = "saved"
            ArrReadingList(3).nbunread = nbSaved
            ArrReadingList(3).xml = xmlSaved     ' Add the saved items list XML in the array of reading lists
            ' If this the first load, initialize current reading list with all the new fetched items
            If nbSaved > 0 Then
                TreeViewMenu.Nodes(0).Nodes(1).Text = TreeViewMenu.Nodes(0).Nodes(1).Tag & " (" & nbSaved & ")"
            Else
                TreeViewMenu.Nodes(0).Nodes(1).Text = TreeViewMenu.Nodes(0).Nodes(1).Tag
            End If
            If firstLoad = "1" Then DoWaitRefreshStatus(My.Resources._code_saved_items_list, "end")

            If firstLoad = "1" Then DoWaitRefreshStatus(My.Resources._code_all_reading_list, "new")
            unreadAll = 0
            ' Fetch ids of unread items and calcultate how many they are
            ' Request : [serverURL]?api=xml&saved_item_ids
            wdata = functions.WRequest(serverURL & "/", "POST", "api=xml&unread_item_ids&api_key=" & functions.APIKey)
            ObjXmlUnreadCount.LoadXml(wdata)
            unreadIds = ObjXmlUnreadCount.DocumentElement.SelectSingleNode("unread_item_ids").InnerText

            ' Update the unread counters of all the subscriptions

            ' Call the fetching all items XML feed function
            ' Used only on the first load, next use the internal reading list operated by the code
            If firstLoad = "1" Then
                xmlRead = xmlfeedread.Clone
            Else
                xmlRead = ArrReadingList(0).xml
            End If

            ArrReadingList(0).name = "read"
            ArrReadingList(0).nbunread = 0
            ' Add all items list XML to the array of reading lists
            ArrReadingList(0).xml = xmlRead     ' Add all the read fetched items
            ' If this the first load, initialize current reading list with all the new fetched items

            ' Call the fetching unread items feed XML function
            xmlUnread = functions.GetFeedXML(unreadIds, "unread")

            ' Update the counter of all the unread items

            If unreadIds = "" Then
                unreadAll = 0
            Else
                Dim nodeList As XmlNodeList = xmlUnread.DocumentElement.SelectNodes("items/item")
                For Each node As XmlNode In nodeList
                    If node.SelectSingleNode("is_spark").InnerText = "0" Then
                        unreadAll += 1
                    Else        ' Delete item belonging to a spark feed
                        node.ParentNode.RemoveChild(node)
                    End If
                Next

            End If


            ArrReadingList(1).name = "unread"
            ArrReadingList(1).nbunread = unreadAll
            ' Add XML feed of unread items in the array of reading lists
            ArrReadingList(1).xml = xmlUnread
            ' If this the first load, initialize current reading list with all the new fetched items

            ' Reset all the counters
            For i = 0 To UBound(ArrFeedsGroup)
                ArrFeedsGroup(i).nbunread = 0
            Next
            For i = 0 To UBound(ArrSubscriptionsGroup)
                ArrSubscriptionsGroup(i).nbunread = 0
            Next

            If unreadAll > 0 Then
                Dim nodeList As XmlNodeList = xmlUnread.DocumentElement.SelectNodes("items/item")
                For Each node As XmlNode In nodeList
                    If node.SelectSingleNode("is_read").InnerText = "0" Then        ' Only process unread items

                        ' Look for the number of unread items by feed
                        For i = 0 To UBound(ArrFeedsGroup)
                            If ArrFeedsGroup(i).id = node.SelectSingleNode("feed_id").InnerText Then
                                ArrFeedsGroup(i).nbunread += 1
                                Exit For
                            End If
                        Next

                        ' Look for the number of unread items by group
                        For i = 0 To UBound(ArrSubscriptionsGroup)
                            If ArrSubscriptionsGroup(i).id = node.SelectSingleNode("group_id").InnerText Then
                                ArrSubscriptionsGroup(i).nbunread += 1
                                Exit For
                            End If
                        Next

                    End If
                Next
            End If

            ' Establishment of the list of all items, we have to merge read and unread items reading lists
            ArrReadingList(2).name = "all"
            ArrReadingList(2).nbunread = unreadAll
            ArrReadingList(2).xml = ArrReadingList(0).xml.Clone
            ' If this the first load, initialize current reading list with all the new fetched items
            ' Add XML feed of unread items
            Dim nodelistUnread As XmlNodeList = ArrReadingList(1).xml.DocumentElement.SelectNodes("items/item")
            For Each node As XmlNode In nodelistUnread
                Dim nodeImport = ArrReadingList(2).xml.ImportNode(node, True)
                ArrReadingList(2).xml.DocumentElement.SelectSingleNode("items").AppendChild(nodeImport)
            Next

            ' Establishment of the "hot" list
            ArrReadingList(4).xml = functions.MakeHotList()

            ' Update the "All items" counter
            If unreadAll > 0 Then
                If unreadAll = 1 Then
                    NotifyIcon.BalloonTipText = My.Resources._code_notify_one_unread_item
                    NotifyIcon.Text = My.Resources._code_notify_one_unread_item
                Else
                    NotifyIcon.BalloonTipText = unreadAll & " " & My.Resources._code_notify_unread_items
                    NotifyIcon.Text = unreadAll & " " & My.Resources._code_notify_unread_items
                End If
                Dim oNode As TreeNode = TreeViewMenu.Nodes(0).Nodes(0)
                oNode.NodeFont = New Font(TreeViewMenu.Font, FontStyle.Bold)
                oNode.Text = TreeViewMenu.Nodes(0).Nodes(0).Tag & " (" & unreadAll & ")"
            Else
                NotifyIcon.BalloonTipText = My.Resources._code_notify_no_unread_item
                NotifyIcon.Text = My.Resources._code_notify_no_unread_item
                Dim oNode As TreeNode = TreeViewMenu.Nodes(0).Nodes(0)
                oNode.NodeFont = New Font(TreeViewMenu.Font, FontStyle.Regular)
                oNode.Text = TreeViewMenu.Nodes(0).Nodes(0).Tag
            End If
            TreeViewMenu.Refresh()

            ' Update the counters by groups
            For i = 0 To UBound(ArrSubscriptionsGroup)
                If ArrSubscriptionsGroup(i).nbunread > 0 Then
                    Dim oNode As TreeNode
                    oNode = functions.TreeviewGetNodeByTag(TreeViewMenu.Nodes(1).Nodes, ArrSubscriptionsGroup(i).name)
                    oNode.NodeFont = New Font(TreeViewMenu.Font, FontStyle.Bold)
                    oNode.Text = ArrSubscriptionsGroup(i).name & " (" & ArrSubscriptionsGroup(i).nbunread & ")"
                Else
                    Dim oNode As TreeNode
                    oNode = functions.TreeviewGetNodeByTag(TreeViewMenu.Nodes(1).Nodes, ArrSubscriptionsGroup(i).name)
                    oNode.NodeFont = New Font(TreeViewMenu.Font, FontStyle.Regular)
                    oNode.Text = ArrSubscriptionsGroup(i).name
                End If
            Next

            ' Update the counters by feeds
            For i = 0 To UBound(ArrFeedsGroup)
                ' Don't take into account spark feeds not displayed in the treeview
                If ArrFeedsGroup(i).is_spark = "0" Then
                    If ArrFeedsGroup(i).nbunread > 0 Then
                        Dim oNode As TreeNode
                        oNode = functions.TreeviewGetNodeByTag(TreeViewMenu.Nodes(1).Nodes, ArrFeedsGroup(i).name)
                        oNode.NodeFont = New Font(TreeViewMenu.Font, FontStyle.Bold)
                        oNode.Text = ArrFeedsGroup(i).name & " (" & ArrFeedsGroup(i).nbunread & ")"
                    Else
                        Dim oNode As TreeNode
                        oNode = functions.TreeviewGetNodeByTag(TreeViewMenu.Nodes(1).Nodes, ArrFeedsGroup(i).name)
                        oNode.NodeFont = New Font(TreeViewMenu.Font, FontStyle.Regular)
                        oNode.Text = ArrFeedsGroup(i).name
                    End If
                End If
            Next
            If firstLoad = "1" Then DoWaitRefreshStatus(My.Resources._code_all_reading_list, "end")

            TreeViewMenu.Refresh()

        Catch ex As Exception
            MessageBox.Show(My.Resources._code_error_updating_counters & " " & ex.Message)
        End Try
    End Sub

    Private Sub UpdateEntryStatus(ByVal entryTag, ByVal status)
        Dim urlfeed, feedName, feednodename, groupnodename, counter, nbUnread, unreadAll, str As String
        Dim indexlist As Integer
        Dim oNodeFeed As TreeNode
        Dim oldnode, newnode As XmlNode
        Dim nodelist As XmlNodeList
        Dim xmllist As XmlDocument

        Try

            ' Look for the list wherein is the item to modify
            Select Case TreeViewMenu.SelectedNode.Tag
                Case TreeViewMenu.Nodes(0).Nodes(1).Tag
                    ' In saved items list
                    indexlist = 3
                    xmllist = ArrReadingList(3).xml
                    nbUnread = ArrReadingList(2).nbunread      ' Keep the global counter for the unread
                Case Else
                    ' In all items list
                    indexlist = 2
                    xmllist = ArrReadingList(2).xml
                    nbUnread = ArrReadingList(2).nbunread
            End Select

            urlfeed = ""

            Select Case status
                Case "read"                 ' Item has been marked as read
                    nodelist = xmllist.DocumentElement.SelectNodes("items/item")
                    LinkLabelReadStatus.Text = My.Resources._code_mark_unread
                    ' Unbold selected item list
                    ListView.SelectedItems(0).Font = _
                        New Font(ListView.Font.Name, ListView.Font.Size, FontStyle.Regular)

                    ' Update the read status of the item in the corresponding XML stored in the reading list
                    For Each node As XmlNode In nodelist
                        If node.SelectSingleNode("id").InnerText = entryTag Then
                            ' Update XML feed (status = read)
                            oldnode = node.SelectSingleNode("is_read")
                            newnode = xmllist.CreateNode(XmlNodeType.Element, "is_read", oldnode.NamespaceURI)
                            newnode.InnerText = "1"
                            node.ReplaceChild(newnode, oldnode)
                            ' Fetch the item feed URL
                            urlfeed = node.SelectSingleNode("feed_url").InnerText
                            Exit For
                        End If
                    Next

                    ' Update treeview counters : feed + group + all unread
                    ' Update feed counter
                    ' If we are in "hot" list, feed name is indicated in a specific way (no "-")
                    str = ListView.SelectedItems(0).SubItems(1).Text
                    If TreeViewMenu.SelectedNode.Tag = TreeViewMenu.Nodes(0).Nodes(2).Tag Then
                        feedName = str
                    Else
                        feedName = str.Substring(str.IndexOf(" - ") + 3, str.Length - str.IndexOf(" - ") - 3)
                    End If
                    oNodeFeed = functions.TreeviewGetNodeByTag(TreeViewMenu.Nodes(1).Nodes, feedName)
                    If oNodeFeed.Tag = "" Then Exit Sub
                    feednodename = oNodeFeed.Text         ' Only one expected node, don't need a loop
                    counter = feednodename.Substring(InStr(feednodename, "("), InStr(feednodename, ")") - InStr(feednodename, "(") - 1)
                    If counter = "1" Then      ' Only one article was unread, unblod and suppress the parenthesis in the feed name
                        oNodeFeed.Text = oNodeFeed.Tag
                        oNodeFeed.NodeFont = New Font(TreeViewMenu.Font, FontStyle.Regular)
                    Else                        ' If more than one unread item remains just decrease the counter
                        oNodeFeed.Text = oNodeFeed.Tag & " (" & counter - 1 & ")"
                    End If

                    ' Update group name counter if the processed feed is in the subscriptions (other case : saved)
                    If oNodeFeed.Parent.Parent Is Nothing = False Then
                        Dim oNodegroup = oNodeFeed.Parent
                        groupnodename = oNodegroup.Text
                        counter = groupnodename.Substring(InStr(groupnodename, "("), InStr(groupnodename, ")") - InStr(groupnodename, "(") - 1)
                        If counter = "1" Then      ' Only one article was unread, unblod and suppress the parenthesis in the feed name
                            oNodegroup.Text = oNodegroup.Tag
                            oNodegroup.NodeFont = New Font(TreeViewMenu.Font, FontStyle.Regular)
                        Else                        ' If more than one unread item remains just decrease the counter
                            oNodegroup.Text = oNodegroup.Tag & " (" & counter - 1 & ")"
                        End If
                    End If

                    ' Update all unread counter
                    counter = nbUnread
                    If counter = "1" Then      '  Only one article was unread, unblod and suppress the parenthesis in the section
                        TreeViewMenu.Nodes(0).Nodes(0).Text = TreeViewMenu.Nodes(0).Nodes(0).Tag
                        TreeViewMenu.Nodes(0).Nodes(0).NodeFont = New Font(TreeViewMenu.Font, FontStyle.Regular)
                    Else                        ' If more than one unread item remains just decrease the counter
                        TreeViewMenu.Nodes(0).Nodes(0).Text = TreeViewMenu.Nodes(0).Nodes(0).Tag & " (" & counter - 1 & ")"
                    End If
                    ArrReadingList(2).nbunread = nbUnread - 1
                    unreadAll = nbUnread - 1
                    If unreadAll = 0 Then
                        NotifyIcon.BalloonTipText = My.Resources._code_notify_no_unread_item
                        NotifyIcon.Text = My.Resources._code_notify_no_unread_item
                    ElseIf unreadAll = 1 Then
                        NotifyIcon.BalloonTipText = My.Resources._code_notify_one_unread_item
                        NotifyIcon.Text = My.Resources._code_notify_one_unread_item
                    Else
                        NotifyIcon.BalloonTipText = unreadAll & " " & My.Resources._code_notify_unread_items
                        NotifyIcon.Text = unreadAll & " " & My.Resources._code_notify_unread_items
                    End If

                    ' Update read items reading list with the addition of the selected item
                    ' and update of unread reading list with the removal of the selected item
                    ' Look for the item to be marked read in the main reading list
                    nodelist = ArrReadingList(2).xml.DocumentElement.SelectNodes("items/item")
                    For Each node As XmlNode In nodelist
                        If node.SelectSingleNode("id").InnerText = entryTag Then
                            ' Update XML feed (status = read)
                            Dim nodesave = node.SelectSingleNode("is_read")
                            nodesave.InnerText = "1"
                            ' Addition of the item in the read items reading list
                            Dim nodeImport = ArrReadingList(0).xml.ImportNode(node, True)
                            ArrReadingList(0).xml.DocumentElement.SelectSingleNode("items").AppendChild(nodeImport)
                            ' Retrieval of the feed URL of the item
                            urlfeed = node.SelectSingleNode("feed_url").InnerText
                            Exit For
                        End If
                    Next

                    ' Removal of the item in the unread items reading list
                    nodelist = ArrReadingList(1).xml.DocumentElement.SelectNodes("items/item")
                    For Each node As XmlNode In nodelist
                        If node.SelectSingleNode("id").InnerText = entryTag Then
                            node.ParentNode.RemoveChild(node)
                            Exit For
                        End If
                    Next

                Case ("unread")               ' The item has just been marked unread
                    nodelist = xmllist.DocumentElement.SelectNodes("items/item")
                    LinkLabelReadStatus.Text = My.Resources._code_mark_read
                    ' Entry of the list to bold
                    ListView.SelectedItems(0).Font = _
                        New Font(ListView.Font.Name, ListView.Font.Size, FontStyle.Bold)
                    For Each node As XmlNode In nodelist
                        If node.SelectSingleNode("id").InnerText = entryTag Then
                            ' Update of the XML feed (status = unread)
                            oldnode = node.SelectSingleNode("is_read")
                            newnode = xmllist.CreateNode(XmlNodeType.Element, "is_read", oldnode.NamespaceURI)
                            newnode.InnerText = "0"
                            oldnode.ParentNode.ReplaceChild(newnode, oldnode)
                            ' Retrieval of the item feed URL
                            urlfeed = node.SelectSingleNode("feed_url").InnerText
                            Exit For
                        End If
                    Next

                    ' Update of the counters in the treeview : feed + group + total unread
                    ' Update feed counter
                    ' If we are in "hot" list, feed name is indicated in a specific way (no "-")
                    str = ListView.SelectedItems(0).SubItems(1).Text
                    If TreeViewMenu.SelectedNode.Tag = TreeViewMenu.Nodes(0).Nodes(2).Tag Then
                        feedName = str
                    Else
                        feedName = str.Substring(str.IndexOf(" - ") + 3, str.Length - str.IndexOf(" - ") - 3)
                    End If
                    oNodeFeed = functions.TreeviewGetNodeByTag(TreeViewMenu.Nodes(1).Nodes, feedName)
                    If oNodeFeed.Tag = "" Then Exit Sub
                    feednodename = oNodeFeed.Text         ' Only one result espected, don't need a loop
                    If oNodeFeed.NodeFont.Bold = False Then    'No item was unread, bold the text and initialize counter to 1
                        oNodeFeed.Text = oNodeFeed.Tag & " (1)"
                        oNodeFeed.NodeFont = New Font(TreeViewMenu.Font, FontStyle.Bold)
                    Else        ' There are already unread items, just increase the counter
                        counter = feednodename.Substring(InStr(feednodename, "("), InStr(feednodename, ")") - InStr(feednodename, "(") - 1)
                        oNodeFeed.Text = oNodeFeed.Tag & " (" & counter + 1 & ")"
                    End If

                    ' Update group counter if the feed is in the subscriptions (other case : saved)
                    If oNodeFeed.Parent.Parent Is Nothing = False Then
                        Dim oNodegroup = oNodeFeed.Parent
                        groupnodename = oNodegroup.Text
                        If oNodegroup.NodeFont.Bold = False Then    ' No item was unread inside the group, bold the text and initialize counter to 1
                            oNodegroup.Text = oNodegroup.Tag & " (1)"
                            oNodegroup.NodeFont = New Font(TreeViewMenu.Font, FontStyle.Bold)
                        Else        ' There are already unread items in the group, just increase the counter
                            counter = groupnodename.Substring(InStr(groupnodename, "("), InStr(groupnodename, ")") - InStr(groupnodename, "(") - 1)
                            oNodegroup.Text = oNodegroup.Tag & " (" & counter + 1 & ")"
                        End If
                    End If

                    ' Update all unread counter, use global variable unreadAll
                    counter = nbUnread
                    If counter = "0" Then      ' No item unread, bold the text and initialize counter to 1
                        TreeViewMenu.Nodes(0).Nodes(0).Text = TreeViewMenu.Nodes(0).Nodes(0).Tag & " (1)"
                        TreeViewMenu.Nodes(0).Nodes(0).NodeFont = New Font(TreeViewMenu.Font, FontStyle.Bold)
                    Else                        ' There are some unread items, just increase the counter
                        TreeViewMenu.Nodes(0).Nodes(0).Text = TreeViewMenu.Nodes(0).Nodes(0).Tag & " (" & counter + 1 & ")"
                    End If
                    ArrReadingList(2).nbunread = nbUnread + 1
                    unreadAll = nbUnread + 1
                    If unreadAll = 1 Then
                        NotifyIcon.BalloonTipText = My.Resources._code_notify_one_unread_item
                        NotifyIcon.Text = My.Resources._code_notify_one_unread_item
                    Else
                        NotifyIcon.BalloonTipText = unreadAll & " " & My.Resources._code_notify_unread_items
                        NotifyIcon.Text = unreadAll & " " & My.Resources._code_notify_unread_items
                    End If

                    ' Update read items reading list with the removal of the selected item 
                    ' and update of unread reading list with the addition of the selected item
                    ' Look for the item to be marked unread in the main reading list
                    nodelist = ArrReadingList(2).xml.DocumentElement.SelectNodes("items/item")
                    For Each node As XmlNode In nodelist
                        If node.SelectSingleNode("id").InnerText = entryTag Then
                            ' Update XML feed (status = read)
                            Dim noderead = node.SelectSingleNode("is_read")
                            noderead.InnerText = "0"
                            ' Addition of the item in the unread items reading list
                            Dim nodeImport = ArrReadingList(1).xml.ImportNode(node, True)
                            ArrReadingList(1).xml.DocumentElement.SelectSingleNode("items").AppendChild(nodeImport)
                            ' Retrieve item feed URL
                            urlfeed = node.SelectSingleNode("feed_url").InnerText
                            Exit For
                        End If
                    Next

                    ' Removal of the item in the read items reading list
                    nodelist = ArrReadingList(0).xml.DocumentElement.SelectNodes("items/item")
                    For Each node As XmlNode In nodelist
                        If node.SelectSingleNode("id").InnerText = entryTag Then
                            node.ParentNode.RemoveChild(node)
                            Exit For
                        End If
                    Next

                Case "saved"              ' The item has been marked saved
                    LinkLabelStar.Text = My.Resources._code_mark_unsaved
                    ' Entry of the list to mark with a star
                    ListView.SelectedItems(0).ImageIndex = 0
                    ' Update saved items counter
                    counter = ArrReadingList(3).nbunread
                    If counter = "0" Then
                        TreeViewMenu.Nodes(0).Nodes(1).Text = TreeViewMenu.Nodes(0).Nodes(1).Tag & " (1)"
                    Else
                        TreeViewMenu.Nodes(0).Nodes(1).Text = TreeViewMenu.Nodes(0).Nodes(1).Tag & " (" & counter + 1 & ")"
                    End If
                    ' Use the field "nbunread" as the items counter so it is increased
                    ArrReadingList(3).nbunread = counter + 1

                    ' Update saved items reading list with the addition of the selected item
                    ' Look for the item saved in the main reading list
                    nodelist = ArrReadingList(2).xml.DocumentElement.SelectNodes("items/item")
                    For Each node As XmlNode In nodelist
                        If node.SelectSingleNode("id").InnerText = entryTag Then
                            ' Update XML feed (status = saved)
                            Dim nodesave = node.SelectSingleNode("is_saved")
                            nodesave.InnerText = "1"
                            ' Retrieve the item in the main reading list and add it in the saved items reading list
                            Dim nodeImport = ArrReadingList(3).xml.ImportNode(node, True)
                            ArrReadingList(3).xml.DocumentElement.SelectSingleNode("items").AppendChild(nodeImport)
                            ' Retrieve the item feed URL
                            urlfeed = node.SelectSingleNode("feed_url").InnerText
                            Exit For
                        End If
                    Next

                Case "unsaved"            ' The item has just been marked unsaved
                    LinkLabelStar.Text = My.Resources._code_mark_saved
                    ' Remove the star of the entry of the list
                    ListView.SelectedItems(0).ImageIndex = -1
                    ' Update saved items counter
                    counter = ArrReadingList(3).nbunread
                    If counter = "1" Then
                        TreeViewMenu.Nodes(0).Nodes(1).Text = TreeViewMenu.Nodes(0).Nodes(1).Tag
                    Else
                        TreeViewMenu.Nodes(0).Nodes(1).Text = TreeViewMenu.Nodes(0).Nodes(1).Tag & " (" & counter - 1 & ")"
                    End If
                    ' Use the field "nbunread" as the items counter so it is decreased
                    ArrReadingList(3).nbunread = counter - 1

                    ' Update saved items reading list with the removal of the selected item
                    ' Look for the item unsaved in the saved reading list
                    nodelist = ArrReadingList(3).xml.DocumentElement.SelectNodes("items/item")
                    For Each node As XmlNode In nodelist
                        If node.SelectSingleNode("id").InnerText = entryTag Then
                            node.ParentNode.RemoveChild(node)             ' Supprime l'élément de la liste de sauvegardés
                            Exit For
                        End If
                    Next

                    ' Mark the item as unsaved in the main reading list
                    nodelist = ArrReadingList(2).xml.DocumentElement.SelectNodes("items/item")
                    For Each node As XmlNode In nodelist
                        If node.SelectSingleNode("id").InnerText = entryTag Then
                            Dim nodesave = node.SelectSingleNode("is_saved")
                            nodesave.InnerText = "0"
                            Exit For
                        End If
                    Next
            End Select

        Catch ex As Exception
            MessageBox.Show(My.Resources._code_error_while_updating_entry_status & " " & ex.Message)
        End Try
    End Sub

    Private Sub Treeview_NodeClick(sender As Object, e As TreeNode)
        Dim onode As TreeNode = e

        Select Case onode.Tag

            Case TreeViewMenu.Nodes(0).Tag               ' Shortcuts
            Case TreeViewMenu.Nodes(0).Nodes(0).Tag      ' All items
                CollapseNodeFlux()
                DoWaitRefresh()
                LinkLabelAll.Enabled = True
                LinkLabelUnread.Enabled = True
                Select Case LinkLabelAll.Font.Bold
                    Case "true"     ' Process the list of all fetched items (read and unread)
                        ' Force an update to reading list to ensure it has always the latest unread items
                        DoList(ArrReadingList(2).xml, onode)
                    Case "false"    ' Fetch the list of the unread items
                        ' Force an update to reading list to ensure it has always the latest unread items
                        DoList(ArrReadingList(1).xml, onode)
                End Select
            Case TreeViewMenu.Nodes(0).Nodes(1).Tag      ' Saved items
                CollapseNodeFlux()
                DoWaitRefresh()
                LinkLabelAll.Enabled = False
                LinkLabelUnread.Enabled = False
                ' Force an update to reading list to ensure it has always the latest unread items
                DoList(ArrReadingList(3).xml, onode)
            Case TreeViewMenu.Nodes(0).Nodes(2).Tag      '"Hot" List
                CollapseNodeFlux()
                DoWaitRefresh()
                LinkLabelAll.Enabled = False
                LinkLabelUnread.Enabled = False
                DoList(ArrReadingList(4).xml, onode)
            Case TreeViewMenu.Nodes(1).Tag              ' Subscriptions
                CollapseNodeFlux()
            Case Else
                ' One group or feed has been selected
                ' If a user has selected a feed, keep it in memory to reduce its parent later
                If onode.Parent.IsExpanded And onode.Parent.Tag <> TreeViewMenu.Nodes(1).Tag Then oNodeSelected = onode
                LinkLabelAll.Enabled = True
                LinkLabelUnread.Enabled = True
                DoWaitRefresh()
                Select Case LinkLabelAll.Font.Bold
                    Case "true"     ' Process the list of all fetched items (read and unread)
                        ' Force an update to reading list to ensure it has always the latest unread items
                        DoList(ArrReadingList(2).xml, onode)
                    Case "false"    ' Fetch the list of the unread items
                        ' Force an update to reading list to ensure it has always the latest unread items
                        DoList(ArrReadingList(1).xml, onode)
                End Select
        End Select

    End Sub

    ' Make the list of current selection items
    Private Sub DoList(ByVal ObjXml As XmlDocument, ByVal oNodeSelected As TreeNode)
        Dim site, filter As String
        Dim htmlwebbrowser, htmlbeforecontent, htmlcontent, htmlaftercontent As String
        Dim i, j, nbentries, saved, oldestunread, towork, group_id As Integer
        Dim dateBackColor, headBackEvenColor, headBackOddColor, headTopLink As Color
        Dim TabListHead(0, 0) As ListViewItem
        Dim TabListDate(0, 0) As ListViewItem
        Dim objXmlStar As XmlDocument
        Dim nodeList, nodeListStar As XmlNodeList
        Dim itemListHead, itemListDate, itemlistTemperature, itemListTopHead As ListViewItem

        nbentries = 0

        ListView.Items.Clear()

        ' If we make the "hot" list, the process is specific (different XML structure) and don't need to make filtering
        If oNodeSelected.Tag = TreeViewMenu.Nodes(0).Nodes(2).Tag Then
            nodeList = ObjXml.DocumentElement.SelectNodes("links/link")
            filter = "all"
            ' Number of items = number of links + total number of items associated to each link
            nbentries = nodeList.Count
            For Each nodeLink As XmlNode In nodeList
                Dim item_ids = nodeLink.SelectSingleNode("item_ids").InnerText
                Dim nbItems = item_ids.Split(",")
                nbentries = nbentries + nbItems.Length
            Next
        Else

            nodeList = ObjXml.DocumentElement.SelectNodes("items/item")

            ' List to do = all items or saved items : don't need to filter incoming XML feed
            If oNodeSelected.Tag = TreeViewMenu.Nodes(0).Nodes(0).Tag Or oNodeSelected.Tag = TreeViewMenu.Nodes(0).Nodes(1).Tag Then
                filter = "all"
                nbentries = nodeList.Count
            Else
                If oNodeSelected.Parent.Tag = TreeViewMenu.Nodes(1).Tag Then        ' Filter XML document by group (oNodeSelected.Tag)
                    filter = "group"
                Else                                                                ' Filter XML document by feed (oNodeSelected.Tag)
                    filter = "feed"
                End If
                For Each node As XmlNode In nodeList
                    If node.SelectSingleNode(filter & "_name").InnerText = oNodeSelected.Tag Then nbentries += 1
                Next
            End If

        End If

        If nbentries = 0 Then       ' Empty list

            itemListHead = ListView.Items.Add(My.Resources._code_no_item_in_this_category)
            With itemListHead
                .Tag = "info"
                .Font = New Font(ListView.Font.Name, ListView.Font.Size, FontStyle.Bold)
                .SubItems.Add(My.Resources._code_choose_another_item_category)
            End With

            ListView.Refresh()

            LinkLabelReadStatus.Visible = False
            LinkLabelStar.Visible = False
            LinkLabelReadability.Visible = False
            LinkLabelUnread.Enabled = False
            LinkLabelMailArticle.Visible = False
            LinkLabelMailLink.Visible = False
            LinkLabelShareFB.Visible = False
            LinkLabelTwittLink.Visible = False

            htmlDefault = My.Resources.reader_default
            WebBrowser.DocumentText = htmlDefault
            WebbrowserBackImg.Visible = True

        Else                    ' Non-empty list

            dateBackColor = Color.LightYellow
            headBackEvenColor = Color.AliceBlue
            headBackOddColor = Color.GhostWhite
            headTopLink = Color.Lavender
            group_id = 0

            i = 0
            ListView.TileSize = New Size(ListView.Width - 40, 41)   ' Height of 41 is the minimal value to have all 3 lines displayed

            ' If we make the "hot" list, specific processing (different XML struture and different elements in the XML)
            If oNodeSelected.Tag = TreeViewMenu.Nodes(0).Nodes(2).Tag Then

                ReDim ArrHotLinksList(nodeList.Count - 1)
                ReDim ArrHotLinksListItems(nbentries - nodeList.Count - 1)
                j = 0

                For Each node As XmlNode In nodeList

                    Try

                        ' Fill the ListeHotLinks structure
                        With ArrHotLinksList(i)
                            .id = node.SelectSingleNode("item_id").InnerText
                            .feed_id = node.SelectSingleNode("feed_id").InnerText
                            .item_id = node.SelectSingleNode("item_id").InnerText
                            .temperature = node.SelectSingleNode("temperature").InnerText
                            .is_item = node.SelectSingleNode("is_item").InnerText
                            .is_local = node.SelectSingleNode("is_local").InnerText
                            .is_saved = node.SelectSingleNode("is_saved").InnerText
                            .title = node.SelectSingleNode("title").InnerText
                            .url = node.SelectSingleNode("url").InnerText
                            .item_ids = node.SelectSingleNode("item_ids").InnerText
                        End With

                        i += 1

                        ' Look for détails about each item attached to the link in process
                        Dim nodeListItem As XmlNodeList = node.SelectNodes("item")

                        For Each nodeItem As XmlNode In nodeListItem

                            Dim dt As DateTime = functions.TimestampToDateTime(nodeItem.SelectSingleNode("created_on_time").InnerText)
                            Dim clear_title = functions.ReplaceHtmlEntities(nodeItem.SelectSingleNode("title").InnerText)
                            ' Make the item preview web page
                            htmlbeforecontent = "<html>" & htmlStyle & "<body><table class=""title""><tr><td><h1><a href=""http://www.instapaper.com/m?u=" & _
                            nodeItem.SelectSingleNode("url").InnerText & """>" & clear_title & "</a></h1><div class=""subtitle"">" & nodeItem.SelectSingleNode("feed_name").InnerText & _
                            "<br/><i>" & dt.ToString("f") & "</i></div></td></tr></table><br/>"
                            htmlcontent = "<div>" & nodeItem.SelectSingleNode("html").InnerText & "</div>"
                            htmlaftercontent = "</body></html>"
                            htmlwebbrowser = htmlbeforecontent & htmlcontent & htmlaftercontent

                            ' Fill HotLinksListItems structure
                            With ArrHotLinksListItems(j)
                                .id = nodeItem.SelectSingleNode("id").InnerText
                                .feed_id = nodeItem.SelectSingleNode("feed_id").InnerText
                                .title = clear_title
                                .author = nodeItem.SelectSingleNode("author").InnerText
                                .html = nodeItem.SelectSingleNode("html").InnerText
                                .htmlwebbrowser = htmlwebbrowser
                                .htmlbeforecontent = htmlbeforecontent
                                .htmlcontent = htmlcontent
                                .htmlaftercontent = htmlaftercontent
                                .url = nodeItem.SelectSingleNode("url").InnerText
                                .is_saved = nodeItem.SelectSingleNode("is_saved").InnerText
                                .is_read = nodeItem.SelectSingleNode("is_read").InnerText
                                .created_on_time = nodeItem.SelectSingleNode("created_on_time").InnerText
                                .feed_name = nodeItem.SelectSingleNode("feed_name").InnerText
                                .group_id = nodeItem.SelectSingleNode("group_id").InnerText
                                .group_name = nodeItem.SelectSingleNode("group_name").InnerText
                            End With

                            j += 1

                        Next

                    Catch ex As Exception
                        MessageBox.Show(My.Resources._code_error_creating_hot_list & " " & ex.Message)
                    End Try

                Next

                For i = 0 To UBound(ArrHotLinksList)

                    If i = 0 Then       ' First line of the list is always a temperature
                        itemlistTemperature = ListView.Items.Add(ArrHotLinksList(i).temperature & " °")
                        With itemlistTemperature
                            .Tag = "temperature"
                            .BackColor = dateBackColor
                            .Font = New Font(ListView.Font.Name, ListView.Font.Size + 3, FontStyle.Bold)
                        End With
                    Else        ' Display a temperature line only if the actual one is different that the previous one
                        If ArrHotLinksList(i).temperature <> ArrHotLinksList(i - 1).temperature Then
                            itemlistTemperature = ListView.Items.Add(ArrHotLinksList(i).temperature & " °")
                            With itemlistTemperature
                                .Tag = "temperature"
                                .BackColor = dateBackColor
                                .Font = New Font(ListView.Font.Name, ListView.Font.Size + 3, FontStyle.Bold)
                            End With
                        End If
                    End If

                    site = ""
                    If ArrHotLinksList(i).is_item = "0" Then
                        ' The link is not attached to a local item, fill the title with it's domain name
                        site = functions.ExtractDomainFromURL(ArrHotLinksList(i).url)
                    Else        ' else retrieve the site name attached to the link
                        For j = 0 To UBound(ArrFeedsGroup)
                            If ArrFeedsGroup(j).id = ArrHotLinksList(i).feed_id Then
                                saved = 0
                                site = ArrFeedsGroup(j).name

                                ' Look if the item is saved
                                objXmlStar = ArrReadingList(3).xml         ' Load saved items reading list
                                nodeListStar = objXmlStar.DocumentElement.SelectNodes("items/item")
                                For Each nodeStar As XmlNode In nodeListStar
                                    If nodeStar.SelectSingleNode("id").InnerText = ArrFeedsGroup(j).id Then
                                        saved = 1       ' Current item was saved
                                        Exit For
                                    End If
                                Next
                                Exit For
                            End If
                        Next
                    End If
                    itemListTopHead = ListView.Items.Add(ArrHotLinksList(i).title)
                    With itemListTopHead
                        ' If the link doesn't come from a local item, mark it with the tag = -1 and the URL to open it
                        If ArrHotLinksList(i).is_item = "0" Then .Tag = "-1:" & ArrHotLinksList(i).url _
                            Else .Tag = ArrHotLinksList(i).id
                        .BackColor = headTopLink
                        .Font = New Font(ListView.Font.Name, ListView.Font.Size + 1, FontStyle.Bold)
                        ' If related item is unread, bold the text. 
                        ' Note : related item is always the last item of the children related to the link
                        If ArrHotLinksListItems(UBound(ArrHotLinksListItems)).is_read = "0" Then
                            .Font = New Font(ListView.Font.Name, ListView.Font.Size, FontStyle.Bold)
                        Else
                            .Font = New Font(ListView.Font.Name, ListView.Font.Size, FontStyle.Regular)
                        End If
                        .SubItems.Add(site)
                        If saved = 1 Then .ImageIndex = 0 ' If saved article, display the star
                    End With

                    ' Now add references of each item related link
                    Dim ArrIds = ArrHotLinksList(i).item_ids.Split(",")
                    ' Determine if the last related item of the link has to be processed. 
                    ' It is only the case when the link doens't come from an internal item
                    ' If internal, last item is always the same as the parent link, so don't need to process it
                    Dim limit As String
                    If ArrHotLinksList(i).is_local = "1" Then
                        limit = UBound(ArrIds) - 1
                    Else
                        limit = UBound(ArrIds)
                    End If
                    For j = 0 To limit
                        ' Look inside the item list for the one corresponding to the article attached to the link
                        For k = 0 To UBound(ArrHotLinksListItems)
                            saved = 0
                            If ArrIds(j) = ArrHotLinksListItems(k).id Then
                                ' Look if the item is saved
                                objXmlStar = ArrReadingList(3).xml         ' Load saved items reading list
                                nodeListStar = objXmlStar.DocumentElement.SelectNodes("items/item")
                                For Each nodeStar As XmlNode In nodeListStar
                                    If nodeStar.SelectSingleNode("id").InnerText = ArrHotLinksListItems(k).id Then
                                        saved = 1           ' Current item was saved
                                        Exit For
                                    End If
                                Next
                                site = ArrHotLinksListItems(k).feed_name
                                itemListHead = ListView.Items.Add(ArrHotLinksListItems(k).title)
                                With itemListHead
                                    .Tag = ArrHotLinksListItems(k).id
                                    If j Mod 2 = 0 Then
                                        .BackColor = headBackEvenColor
                                    Else
                                        .BackColor = headBackOddColor
                                    End If
                                    ' If related item is unread, bold the text
                                    If ArrHotLinksListItems(k).is_read = "0" Then
                                        .Font = New Font(ListView.Font.Name, ListView.Font.Size, FontStyle.Bold)
                                    Else
                                        .Font = New Font(ListView.Font.Name, ListView.Font.Size, FontStyle.Regular)
                                    End If
                                    .SubItems.Add(site)
                                    If saved = 1 Then .ImageIndex = 0 ' If saved item show the star
                                End With

                                Exit For
                            End If
                        Next
                    Next
                Next

                ListView.Items(1).Selected = True
                LinkLabelUnread.Visible = True
                LinkLabelAll.Visible = True


            Else        ' Make the traditional list

                ReDim TabListHead(nbentries - 1, 1)
                ReDim TabListDate(nbentries - 1, 1)
                ReDim ArrReadingListItems(nbentries - 1)
                oldestunread = 0

                For Each node As XmlNode In nodeList
                    Try
                        ' Reset the indicator; by default, consider the current item doesn't have to be added
                        towork = 0

                        ' List to do = all items or saved items : no need to filter incoming XML feed
                        If filter = "all" Then
                            towork = 1
                            ' Else, process the item only if it matches the selected group or feed
                        ElseIf node.SelectSingleNode(filter & "_name").InnerText = oNodeSelected.Tag Then
                            towork = 1
                        End If

                        ' If the item has been marked to be processed (towork = 1), add it to the list to be displayed
                        If towork = 1 Then

                            Dim dt As DateTime = functions.TimestampToDateTime(node.SelectSingleNode("created_on_time").InnerText)
                            Dim clear_title = functions.ReplaceHtmlEntities(node.SelectSingleNode("title").InnerText)
                            ' Make the item preview web page
                            htmlbeforecontent = "<html>" & htmlStyle & "<body><table class=""title""><tr><td><h1><a href=""http://www.instapaper.com/m?u=" & _
                            node.SelectSingleNode("url").InnerText & """>" & clear_title & "</a></h1><div class=""subtitle"">" & node.SelectSingleNode("feed_name").InnerText & _
                            "<br/><i>" & dt.ToString("f") & "</i></div></td></tr></table><br/>"
                            htmlcontent = "<div>" & node.SelectSingleNode("html").InnerText & "</div>"
                            htmlaftercontent = "</body></html>"
                            htmlwebbrowser = htmlbeforecontent & htmlcontent & htmlaftercontent

                            ' Fill the ListeElements structure
                            ArrReadingListItems(i) = New ItemsLists() With { _
                                .id = node.SelectSingleNode("id").InnerText, _
                                .feed_id = node.SelectSingleNode("feed_id").InnerText, _
                                .title = clear_title, _
                                .author = node.SelectSingleNode("author").InnerText, _
                                .html = node.SelectSingleNode("html").InnerText, _
                                .htmlwebbrowser = htmlwebbrowser, .htmlbeforecontent = htmlbeforecontent, _
                                .htmlcontent = htmlcontent, .htmlaftercontent = htmlaftercontent, _
                                .url = node.SelectSingleNode("url").InnerText, _
                                .is_saved = node.SelectSingleNode("is_saved").InnerText, _
                                .is_read = node.SelectSingleNode("is_read").InnerText, _
                                .created_on_time = node.SelectSingleNode("created_on_time").InnerText, _
                                .feed_name = node.SelectSingleNode("feed_name").InnerText, _
                                .group_id = node.SelectSingleNode("group_id").InnerText, _
                                .group_name = node.SelectSingleNode("group_name").InnerText}

                            i += 1
                        End If
                    Catch ex As Exception
                        MessageBox.Show(My.Resources._code_error_creating_reading_list & " " & ex.Message)
                    End Try

                Next

                Array.Sort(ArrReadingListItems)

                dateBackColor = Color.LightYellow
                headBackEvenColor = Color.AliceBlue
                headBackOddColor = Color.GhostWhite

                ' Process the items in descending order, from the most recent to the oldest
                For i = UBound(ArrReadingListItems) To 0 Step -1

                    saved = 0
                    site = ArrReadingListItems(i).feed_name
                    Dim dt As DateTime = functions.TimestampToDateTime(ArrReadingListItems(i).created_on_time)

                    If i = UBound(ArrReadingListItems) Then            ' The first displayed line is always a date
                        itemListDate = ListView.Items.Add(dt.ToString("dddd") & " " & dt.ToString("M"))
                        With itemListDate
                            .Tag = "date"
                            .BackColor = dateBackColor
                            .Font = New Font(ListView.Font.Name, ListView.Font.Size + 3, FontStyle.Bold)
                        End With
                    Else                    ' Display a date line if the date of the current item is different than the previous item one
                        Dim dt_previous As DateTime = functions.TimestampToDateTime(ArrReadingListItems(i + 1).created_on_time)
                        If dt.ToString("dddd") & " " & dt.ToString("M") <> dt_previous.ToString("dddd") & " " & dt_previous.ToString("M") Then
                            itemListDate = ListView.Items.Add(dt.ToString("dddd") & " " & dt.ToString("M"))
                            With itemListDate
                                .Tag = "date"
                                .BackColor = dateBackColor
                                .Font = New Font(ListView.Font.Name, ListView.Font.Size + 3, FontStyle.Bold)
                            End With
                        End If
                    End If

                    ' If we make the saved items list, always add a star to report the item as saved
                    If oNodeSelected.Tag = TreeViewMenu.Nodes(0).Nodes(1).Tag Then
                        saved = 1
                        ' Else mark only items that are in the saved items reading list
                    Else
                        objXmlStar = ArrReadingList(3).xml         ' Load saved items reading list
                        nodeListStar = objXmlStar.DocumentElement.SelectNodes("items/item")
                        For Each nodeStar As XmlNode In nodeListStar
                            If nodeStar.SelectSingleNode("id").InnerText = ArrReadingListItems(i).id Then
                                saved = 1
                                Exit For
                            End If
                        Next
                    End If

                    itemListHead = ListView.Items.Add(ArrReadingListItems(i).title)
                    With itemListHead
                        ' Instruction used to have always 2 lines title rows even when title is short enough to fetch on one row
                        If Len(ArrReadingListItems(i).title) < 50 Then .Text = .Text & "                                              "
                        .Tag = ArrReadingListItems(i).id
                        If i Mod 2 = 0 Then
                            .BackColor = headBackEvenColor
                        Else
                            .BackColor = headBackOddColor
                        End If
                        ' If the item is unread, bold the text
                        If ArrReadingListItems(i).is_read = "0" Then
                            .Font = New Font(ListView.Font.Name, ListView.Font.Size, FontStyle.Bold)
                        Else
                            .Font = New Font(ListView.Font.Name, ListView.Font.Size, FontStyle.Regular)
                        End If
                        If saved = 1 Then .ImageIndex = 0 ' If saved item, display the star
                        .SubItems.Add(dt.ToString("t") & " - " & site)
                    End With

                    ' If current item is unread, save it's position in the list for later selection if it is the last one
                    If ListView.Items(ListView.Items.Count - 1).Font.Bold = True Then
                        oldestunread = ListView.Items.Count - 1
                    End If

                Next


                LinkLabelUnread.Visible = True
                LinkLabelAll.Visible = True

                ' If saved items list is diplayed, select the first one of the list
                If oNodeSelected.Tag = TreeViewMenu.Nodes(0).Nodes(1).Tag Then oldestunread = 1

                ' Select the oldest unread item of the list
                ListView.Items(oldestunread).Selected = True
                ListView.Items(oldestunread).EnsureVisible()
            End If

        End If

    End Sub

    Private Sub ListView_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ListView.SelectedIndexChanged
        Dim htmlwebbrowser, page_title, status As String

        ' Necessary check because the SelectedIndexChanged event is fired more times then intuitively expected. 
        ' Whens witching from a previously selected item to the next one, it's done in two steps: 
        ' in the first one, the selected state changes from something to nothing, SelectedIndexChanged fires, 
        ' and the SelectedIndices returns an empty collection (as nothing in is currently selected); in the second step, 
        ' the new item get's selected, the SelectedIndexChanged event is fired again, 
        ' and this time there will be an entry on SelectedItems[0].
        If ListView.SelectedIndices.Count > 0 Then

            ' If the line selected is not an article head, don't process it
            If ListView.SelectedItems(0).Tag = "info" Or _
                ListView.SelectedItems(0).Tag = "date" Or _
                    ListView.SelectedItems(0).Tag = "temperature" Then Exit Sub

            ' Mark the selected item as read if it is not already marked (so if the text of the line is bolded)
            ' Only if it's a internal item (can be an external in case of "hot" list item)
            If InStr(ListView.SelectedItems(0).Tag, "-1") = 0 Then
                If ListView.SelectedItems(0).Font.Bold = True Then
                    status = functions.ChangeItemState(ListView.SelectedItems(0).Tag, "read")
                    If status = "OK" Then updateEntryStatus(ListView.SelectedItems(0).Tag, "read")
                Else
                    LinkLabelReadStatus.Text = My.Resources._code_mark_unread
                End If
                If ListView.SelectedItems(0).ImageIndex = 0 Then    ' Saved item
                    LinkLabelStar.Text = My.Resources._code_mark_unsaved
                Else                                                ' Unsaved item
                    LinkLabelStar.Text = My.Resources._code_mark_saved
                End If
            End If

            htmlwebbrowser = ""
            page_title = ""

            ' If item selected is in the "hot" list, the content to be displayed is in a dedicated structure
            If TreeViewMenu.SelectedNode.Tag = TreeViewMenu.Nodes(0).Nodes(2).Tag Then
                If InStr(ListView.SelectedItems(0).Tag, "-1") = 1 Then        'External item
                    Dim tag As String = ListView.SelectedItems(0).Tag
                    url_navigation = tag.Substring(3, Len(tag) - 3)
                    WebBrowser.AccessibleDescription = url_navigation
                    LinkLabelReadStatus.Enabled = False
                    LinkLabelStar.Enabled = False
                    WebBrowser.Navigate(url_navigation)
                    Exit Sub
                Else                                                          ' Internal item
                    For i = 0 To UBound(ArrHotLinksListItems)
                        If ArrHotLinksListItems(i).id = ListView.SelectedItems(0).Tag Then
                            LinkLabelReadStatus.Enabled = True
                            LinkLabelStar.Enabled = True
                            htmlwebbrowser = ArrHotLinksListItems(i).htmlwebbrowser
                            url_navigation = ArrHotLinksListItems(i).url
                            WebBrowser.Tag = ArrHotLinksListItems(i).title
                            Exit For
                        End If
                    Next
                End If
            Else            ' Selected item is in traditionnal list (read/unread/saved items)
                For i = 0 To UBound(ArrReadingListItems)
                    If ArrReadingListItems(i).id = ListView.SelectedItems(0).Tag Then
                        LinkLabelReadStatus.Enabled = True
                        LinkLabelStar.Enabled = True
                        htmlwebbrowser = ArrReadingListItems(i).htmlwebbrowser
                        url_navigation = ArrReadingListItems(i).url
                        WebBrowser.Tag = ArrReadingListItems(i).title
                        Exit For
                    End If
                Next
            End If

            ' Keep in an editable property of the webbrowser the URL leading to the full article
            ' for later processing in Instapaper and Readability
            WebBrowser.AccessibleDescription = url_navigation
            ' Hide the background picture visible when no atricle is diplayed on the webbrowser
            WebbrowserBackImg.Visible = False
            ' Load article content (or excerpt of content according to the associated RSS feed)
            WebBrowser.DocumentText = htmlwebbrowser

        End If
    End Sub

    Private Sub WebBrowser_Navigating(sender As Object, e As WebBrowserNavigatingEventArgs) Handles WebBrowser.Navigating
        ' This doesn't wok well, deactivated for now
        'LabelEtat.Font = New Font(Me.Font, FontStyle.Bold)
        'LabelEtat.Text = My.Resources._code_loading_page & " ..."
    End Sub

    Private Sub WebBrowser_Navigated(sender As Object, e As WebBrowserNavigatedEventArgs) Handles WebBrowser.Navigated

        If firstLoad = "0" Then
            LabelChoix.Visible = False
            LabelChoix.Font = New Font(Me.Font, FontStyle.Regular)
            LabelChoix.Text = My.Resources._code_page_loaded
            TimerStatut.Start()
            ListView.Focus()

            ' Ensure an article is selected on the list (if there is an article in the list there is at least 2 items in the list)
            If ListView.Items.Count > 1 Then
                ' Look for the title of the loaded page, only in case of an external link (else we already have it)
                If TreeViewMenu.SelectedNode.Tag = TreeViewMenu.Nodes(0).Nodes(2).Tag And _
                    InStr(ListView.SelectedItems(0).Tag, "-1") = 1 Then
                    WebBrowser.Tag = WebBrowser.DocumentTitle
                End If

                ' If we are in the webbrowser default page, the list is empty so deactivation of the actions available on an article
                If WebBrowser.DocumentTitle = "Fever RSS Reader Default Page" Then
                    LinkLabelReadStatus.Visible = False
                    LinkLabelStar.Visible = False
                    LinkLabelReadability.Visible = False
                    LinkLabelMailArticle.Visible = False
                    LinkLabelMailLink.Visible = False
                    LinkLabelShareFB.Visible = False
                    LinkLabelTwittLink.Visible = False
                Else
                    LinkLabelReadStatus.Visible = True
                    LinkLabelStar.Visible = True
                    LinkLabelReadability.Visible = True
                    LinkLabelMailArticle.Visible = True
                    LinkLabelMailLink.Visible = True
                    LinkLabelShareFB.Visible = True
                    LinkLabelTwittLink.Visible = True
                End If
            End If

        End If
    End Sub

    Private Sub CollapseNodeFlux()
        If oNodeSelected Is Nothing = False Then
            If oNodeSelected.Parent.Tag <> TreeViewMenu.Nodes(1).Tag Then oNodeSelected.Parent.Collapse()
        End If
    End Sub

    Private Sub TreeViewMenu_NodeMouseClick(sender As Object, e As TreeNodeMouseClickEventArgs) Handles TreeViewMenu.NodeMouseClick
        ' If user selects All items, always perform a refresh of the reading list, even if he was already in this view,
        ' to display newer items since last display
        ' Note : when changing selected node on the treeview, it first keeps the old selected one when being on this sub
        ' We have to use a variable here to know whether the user has changed the node selected or not, because if the node hasn't changed, 
        ' the event "After select" is not triggered
        If e.Node.Tag = TreeViewMenu.SelectedNode.Tag Then  ' Here the SelectedNode object is still the previous one
            nodeChanged = "0"
            ' No change so no AfterSelect event triggered, call our update sub code manually
            Treeview_NodeClick(sender, e.Node)
        Else
            nodeChanged = "1"
            ' Right next that sub the AfterSelect event is triggered
        End If
    End Sub

    Private Sub TreeViewMenu_AfterSelect(sender As Object, e As TreeViewEventArgs) Handles TreeViewMenu.AfterSelect
        ' If the user selects All items, update has already been made if it was already the node selected before
        If e.Node.Tag <> My.Resources._code_all_items Or firstLoad = "1" Or nodeChanged = "1" Then Treeview_NodeClick(sender, e.Node)
    End Sub


    Private Sub ListView_KeyDown(sender As Object, e As KeyEventArgs) Handles ListView.KeyDown

        ' Keyboard shortcuts : F9 = Instapaper Mobilizer, F10 = read/unread, F11 = saved/unsaved, F12 = Readability Mobilizer

        If (WebBrowser.AccessibleDescription <> "" And e.KeyValue = Keys.F9) Then
            WebBrowser.Navigate("http://www.instapaper.com/m?u=" & WebBrowser.AccessibleDescription)
        End If

        If (WebBrowser.AccessibleDescription <> "" And e.KeyValue = Keys.F10) Then
            LinkLabelReadStatus_LinkClicked(sender, Nothing)
        End If

        If (WebBrowser.AccessibleDescription <> "" And e.KeyValue = Keys.F11) Then
            LinkLabelStar_LinkClicked(sender, Nothing)
        End If

        If (WebBrowser.AccessibleDescription <> "" And e.KeyValue = Keys.F12) Then
            LinkLabelReadability_LinkClicked(sender, Nothing)
        End If

    End Sub

    ' Clik on the label to parse article with Readability mobilizer
    Private Sub LinkLabelReadability_LinkClicked(sender As Object, e As LinkLabelLinkClickedEventArgs) Handles LinkLabelReadability.LinkClicked
        Dim wdata, htmlbeforecontent, htmlcontent, title, site, date_published As String

        LabelChoix.Font = New Font(Me.Font, FontStyle.Bold)
        LabelChoix.Text = My.Resources._code_loading_page & "..."

        ' Render full article using Readability Parser
        ' Request : https://readability.com/api/content/v1/parser?url=[url]&token=[token]
        wdata = functions.WRequest("https://readability.com/api/content/v1/parser", "GET", _
                "url=" & System.Web.HttpUtility.UrlEncode(WebBrowser.AccessibleDescription) & "&token=" & My.Resources.readabilty_token)
        Try

            ' Parse JSON result given by the request result
            Dim jss = New JavaScriptSerializer()
            Dim jsonResult As Dictionary(Of String, String) = jss.Deserialize(Of Dictionary(Of String, String))(wdata)
            htmlcontent = jsonResult.Item("content").ToString

            ' If we are in the "hot" list, add css style to the article content declared in specific variable
            If TreeViewMenu.SelectedNode.Tag = TreeViewMenu.Nodes(0).Nodes(2).Tag Then
                If InStr(ListView.SelectedItems(0).Tag, "-1") = 1 Then        'External item
                    title = jsonResult("title").ToString
                    site = jsonResult("domain").ToString
                    date_published = jsonResult("date_published").ToString
                    htmlbeforecontent = "<body><table class=""title""><tr><td><h1><a href=""http://www.instapaper.com/m?u=" & _
                            WebBrowser.AccessibleDescription & """>" & title & "</a></h1><div class=""subtitle"">" & site & _
                            "<br/><i>" & date_published & "</i></div></td></tr></table><br/>"
                    WebBrowser.DocumentText = htmlStyle & htmlbeforecontent & htmlcontent
                Else
                    ' Add CSS style to render the full article content
                    For i = 0 To UBound(ArrHotLinksListItems)
                        If ArrHotLinksListItems(i).url = WebBrowser.AccessibleDescription Then
                            WebBrowser.DocumentText = ArrHotLinksListItems(i).htmlbeforecontent & _
                                htmlcontent & ArrReadingListItems(i).htmlaftercontent
                            Exit For
                        End If
                    Next
                End If
            Else    ' Traditionnal list
                ' Add CSS style to render the full article content
                For i = 0 To UBound(ArrReadingListItems)
                    If ArrReadingListItems(i).url = WebBrowser.AccessibleDescription Then
                        WebBrowser.DocumentText = ArrReadingListItems(i).htmlbeforecontent & _
                            htmlcontent & ArrReadingListItems(i).htmlaftercontent
                        Exit For
                    End If
                Next
            End If
        Catch ex As Exception
            MessageBox.Show(My.Resources._code_unable_to_parse_article & " : " & wdata)
        End Try

        LabelChoix.Font = New Font(Me.Font, FontStyle.Regular)
        LabelChoix.Text = My.Resources._code_page_loaded
        TimerStatut.Start()

    End Sub

    Private Sub LinkLabelShareFB_LinkClicked(sender As Object, e As LinkLabelLinkClickedEventArgs) Handles LinkLabelShareFB.LinkClicked
        WebBrowser.Navigate("https://www.facebook.com/sharer/sharer.php?u=" & System.Web.HttpUtility.UrlEncode(WebBrowser.AccessibleDescription))
    End Sub

    Private Sub LinkLabelTwittLink_LinkClicked(sender As Object, e As LinkLabelLinkClickedEventArgs) Handles LinkLabelTwittLink.LinkClicked
        WebBrowser.Navigate("http://twitter.com/share?url=" & System.Web.HttpUtility.UrlEncode(WebBrowser.AccessibleDescription))
    End Sub

    Private Sub LinkLabelMailLink_LinkClicked(sender As Object, e As LinkLabelLinkClickedEventArgs) Handles LinkLabelMailLink.LinkClicked
        System.Diagnostics.Process.Start("mailto:?subject=" & WebBrowser.Tag & "&body=" & My.Resources._code_mail_body_to_read & _
                                         WebBrowser.AccessibleDescription)
    End Sub

    Private Sub LinkLabelMailArticle_LinkClicked(sender As Object, e As LinkLabelLinkClickedEventArgs) Handles LinkLabelMailArticle.LinkClicked
        Dim wdata As String

        ' Render full article using Readability Parser
        ' Request : https://readability.com/api/content/v1/parser?url=[url]&token=[token]
        wdata = functions.WRequest("https://readability.com/api/content/v1/parser", "GET", _
                "url=" & System.Web.HttpUtility.UrlEncode(WebBrowser.AccessibleDescription) & "&token=" & My.Resources.readabilty_token)
        Try

            ' Parse JSON result given by the request result
            Dim jss = New JavaScriptSerializer()
            Dim jsonResult As Dictionary(Of String, String) = jss.Deserialize(Of Dictionary(Of String, String))(wdata)
            Dim htmlcontent = jsonResult.Item("content").ToString

            System.Diagnostics.Process.Start("mailto:?subject=" & WebBrowser.Tag & "&body=" & System.Web.HttpUtility.UrlEncode(htmlcontent))

        Catch
            MsgBox(My.Resources._code_unable_to_parse_article & " : " & wdata)
        End Try

    End Sub

    Private Sub TimerStatut_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TimerStatut.Tick
        LabelChoix.Text = ""
        TimerStatut.Stop()
    End Sub

    ' Clik on a label to mark item as read or unread
    Private Sub LinkLabelReadStatus_LinkClicked(ByVal sender As System.Object, ByVal e As System.Windows.Forms.LinkLabelLinkClickedEventArgs) Handles LinkLabelReadStatus.LinkClicked
        Dim status, urlItem As String
        urlItem = ""

        ' If we are in the "hot" list, information is declared in specific variable
        If TreeViewMenu.SelectedNode.Tag = TreeViewMenu.Nodes(0).Nodes(2).Tag Then
            For i = 0 To UBound(ArrHotLinksListItems)
                If ArrHotLinksListItems(i).id = ListView.SelectedItems(0).Tag Then
                    urlItem = ArrHotLinksListItems(i).url
                    Exit For
                End If
            Next
        Else
            For i = 0 To UBound(ArrReadingListItems)
                If ArrReadingListItems(i).id = ListView.SelectedItems(0).Tag Then
                    urlItem = ArrReadingListItems(i).url
                    Exit For
                End If
            Next
        End If

        If LinkLabelReadStatus.Text = My.Resources._code_mark_read Then
            If urlItem = WebBrowser.AccessibleDescription Then
                If ListView.SelectedItems(0).Font.Bold = True Then
                    status = functions.ChangeItemState(ListView.SelectedItems(0).Tag, "read")
                    If status = "OK" Then UpdateEntryStatus(ListView.SelectedItems(0).Tag, "read")
                End If
            End If
        Else
            If urlItem = WebBrowser.AccessibleDescription Then
                If ListView.SelectedItems(0).Font.Bold = False Then
                    status = functions.ChangeItemState(ListView.SelectedItems(0).Tag, "unread")
                    If status = "OK" Then UpdateEntryStatus(ListView.SelectedItems(0).Tag, "unread")
                End If
            End If
        End If
    End Sub

    ' Clik on a label to mark item saved or unsaved
    Private Sub LinkLabelStar_LinkClicked(ByVal sender As System.Object, ByVal e As System.Windows.Forms.LinkLabelLinkClickedEventArgs) Handles LinkLabelStar.LinkClicked
        Dim status, urlItem As String
        urlItem = ""

        ' If we are in the "hot" list, information is declared in specific variable
        If TreeViewMenu.SelectedNode.Tag = TreeViewMenu.Nodes(0).Nodes(2).Tag Then
            For i = 0 To UBound(ArrHotLinksListItems)
                If ArrHotLinksListItems(i).id = ListView.SelectedItems(0).Tag Then
                    urlItem = ArrHotLinksListItems(i).url
                    Exit For
                End If
            Next
        Else
            For i = 0 To UBound(ArrReadingListItems)
                If ArrReadingListItems(i).id = ListView.SelectedItems(0).Tag Then
                    urlItem = ArrReadingListItems(i).url
                    Exit For
                End If
            Next
        End If

        If LinkLabelStar.Text = My.Resources._code_mark_saved Then
            If urlItem = WebBrowser.AccessibleDescription Then
                If ListView.SelectedItems(0).ImageIndex = -1 Then
                    status = functions.ChangeItemState(ListView.SelectedItems(0).Tag, "saved")
                    If status = "OK" Then UpdateEntryStatus(ListView.SelectedItems(0).Tag, "saved")
                End If
            End If
        Else
            If urlItem = WebBrowser.AccessibleDescription Then
                If ListView.SelectedItems(0).ImageIndex = 0 Then
                    status = functions.ChangeItemState(ListView.SelectedItems(0).Tag, "unsaved")
                    If status = "OK" Then UpdateEntryStatus(ListView.SelectedItems(0).Tag, "unsaved")
                End If
            End If
        End If
    End Sub

End Class
